package thuai.ccf2013.query;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import thuai.ccf2013.util.MyFileReader;

/**
 * The query contains its unique String id, the content and a list of entity.
 * The core process of recognizing xml tags is here, using regex.
 * 
 * @author WangYan
 * 
 */
public class Query {

	private String weiboId = null;

	public String getWeiboId() {
		return weiboId;
	}

	private String content = null;

	public String getContent() {
		return content;
	}

	private List<Entity> entityList = null;
	public List<Entity> getEntityList() {
		return entityList;
	}

	private List<String> urlList = null;

	private static boolean patternInitialized = false;

	/**
	 * The patterns used to parse the query doc.
	 */
	private static Pattern patWeiboId = null;
	private static Pattern patContent = null;
	private static Pattern patNameId = null;
	private static Pattern patStartOffset = null;
	private static Pattern patEndOffset = null;
	private static Pattern patKBId = null;
	private static Pattern patEndWeibo = null;

	private static void initPattern() {
		patWeiboId = Pattern.compile("<weibo\\sid\\s=\\s\"(.*)\"");
		patContent = Pattern.compile("<content>(.*)</content>");
		patNameId = Pattern.compile("<name\\sid\\s=\\s\"(.*)\">(.*)<");
		patStartOffset = Pattern
				.compile("<startoffset\\sid\\s=\\s\"(.*)\">(.*)<");
		patEndOffset = Pattern.compile("<endoffset\\sid\\s=\\s\"(.*)\">(.*)<");
		patKBId = Pattern.compile("kb\\sid\\s=\\s\"(.*)\">(.*)<");
		patEndWeibo = Pattern.compile("<//weibo>");
	}

	/**
	 * Input a list of String in XML-format.
	 * 
	 * @param strList
	 */
	public Query(List<String> strList) {

		if (!patternInitialized) {
			initPattern();
		}

		entityList = new ArrayList<Entity>();

		int prevEntityId = 0;
		String entityName = null, KB = null;
		int startOffset = -1, endOffset = -1;

		for (String line : strList) {
			Matcher matcher = patWeiboId.matcher(line);
			if (matcher.find()) {
				this.weiboId = matcher.group(1);
				continue;
			}
			matcher = patContent.matcher(line);
			if (matcher.find()) {
				this.content = matcher.group(1).toLowerCase();
				continue;
			}
			matcher = patNameId.matcher(line);
			if (matcher.find()) {
				int entityId = Integer.parseInt(matcher.group(1));
				if (entityId != prevEntityId) {
					if (prevEntityId > 0) {
						entityList.add(new Entity(this, entityId, entityName,
								startOffset, endOffset, KB));
					}
					prevEntityId = entityId;
					entityName = null;
					KB = null;
					startOffset = -1;
					endOffset = -1;
				}
				entityName = matcher.group(2).toLowerCase();
				continue;
			}
			matcher = patStartOffset.matcher(line);
			if (matcher.find()) {
				assert (prevEntityId == Integer.parseInt(matcher.group(1))) : matcher
						.group(1);
				startOffset = Integer.parseInt(matcher.group(2));
				continue;
			}
			matcher = patEndOffset.matcher(line);
			if (matcher.find()) {
				assert (prevEntityId == Integer.parseInt(matcher.group(1)));
				endOffset = Integer.parseInt(matcher.group(2));
				continue;
			}
			matcher = patKBId.matcher(line);
			if (matcher.find()) {
				assert (prevEntityId == Integer.parseInt(matcher.group(1)));
				KB = matcher.group(2);
				continue;
			}
			matcher = patEndWeibo.matcher(line);
			if (matcher.find()) {
				continue;
			}
		}
		entityList.add(new Entity(this, prevEntityId, entityName, startOffset,
				endOffset, KB));
	}

	public boolean checkValidation() {
		boolean valid = true;
		if (entityList != null) {
			for (Entity entity : entityList) {
				if (!entity.checkValidation()) {
					System.out.println("Invalid entity: " + entity.toString());
					valid = false;
				}
			}
		}
		return valid;
	}

	/**
	 * Load queries from given file. The file format should be the same with the
	 * sample file. Read the whole content of a query and then parse it.
	 * 
	 * @param file
	 *            the source of queries
	 * @return ArrayList of queries
	 */
	public static List<Query> loadFromFile(String file) {
		List<Query> queryList = new ArrayList<Query>();
		List<String> buffer = new ArrayList<String>();
		MyFileReader reader = new MyFileReader(file);
		String temp = null;
		boolean isPart = false;
		while ((temp = reader.getNextLine()) != null) {
			temp = temp.trim();
			if (isPart) {
				if (temp.startsWith("</weibo")) { // the end of the previous
													// weibo query
					isPart = false;
					queryList.add(new Query(buffer));
				} else {
					buffer.add(temp);
				}
			} else { // a start of a new weibo query
				if (temp.startsWith("<weibo")) {
					isPart = true;
					buffer.clear();
					buffer.add(temp);
				}
			}

		}

		/*
		 * check validation
		 */
		for (Query query : queryList) {
			if (!query.checkValidation()) {
				// System.out.println("Invalid query!");
			}
		}

		return queryList;
	}

	public static List<Entity> mergeQueryList(List<Query> queryList) {
		List<Entity> entityList = new ArrayList<Entity>();
		for (Query query : queryList) {
			entityList.addAll(query.entityList);
		}
		return entityList;
	}

}
